﻿using AutoMapper;
using Marvin.Cache.Headers;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Restful_Api.DtoParameters;
using Restful_Api.Entities;
using Restful_Api.Models;
using Restful_Api.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Restful_Api.Controllers
{
    [ApiController]
    [Route("api/Companies/{companyId}/employees")]
    //设置控制器下的全部action的缓存为120s自定义的缓存对象（看startup定义）
    //[ResponseCache(CacheProfileName = "120sCacheProfile")]
    public class EmployeeController : ControllerBase
    {
        private readonly ICompanyRepository _companyRepository;
        private readonly IMapper mapper;

        public EmployeeController(IMapper mapper, ICompanyRepository companyRepository)
        {
            this.mapper = mapper;            
            _companyRepository = companyRepository;
        }
        [HttpGet(Name =nameof(GetEmployeesForCompany))]
        public async Task<ActionResult<IEnumerable<EmployeeDto>>> GetEmployeesForCompany(Guid companyId, [FromQuery] EmployeeDtoParameters parameters)
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
                return NotFound();
            var employees = await _companyRepository.GetEmployeesAsync(companyId, parameters);
            var emoloyessDtos = mapper.Map<IEnumerable<EmployeeDto>>(employees);
            return Ok(emoloyessDtos);
        }

        [HttpGet("{employeeid}", Name = (nameof(GetEmployeeForComapn)))]
        //设置独立的缓存时间
        //[ResponseCache(Duration =60)]
        //设置独立的缓存验证器
        [HttpCacheExpiration(CacheLocation = CacheLocation.Public, MaxAge = 1800)]
        [HttpCacheValidation(MustRevalidate = false)]
        public async Task<ActionResult<EmployeeDto>> GetEmployeeForComapn(Guid companyId, Guid employeeid)
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
                return NotFound();
            var employee = await _companyRepository.GetEmployeeAsync(companyId, employeeid);
            var emoloyessDto = mapper.Map<EmployeeDto>(employee);
            return Ok(emoloyessDto);
        }
        [HttpPost(Name =nameof(CreateEmployeeForCompany))]
        public async Task<ActionResult<EmployeeDto>> CreateEmployeeForCompany(Guid companyId, EmployeeAddDto employeeAddDto)
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
            {
                return NotFound();
            }
            var employee = mapper.Map<Employee>(employeeAddDto);
            _companyRepository.AddEmployee(companyId, employee);
            await _companyRepository.SaveAsync();

            var employeeDto = mapper.Map<EmployeeDto>(employee);
            return CreatedAtRoute(nameof(GetEmployeeForComapn), new { companyId, employeeid = employeeDto.Id }, employeeDto);
        }


        //整体替换
        [HttpPut("{employeeId}")]
        public async Task<IActionResult> UpdateEmployeeForCompanye(Guid companyId, Guid employeeId, EmployeeUpdateDto updateDto)
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
                return NotFound();
            var employeeEnitiy = await _companyRepository.GetEmployeeAsync(companyId, employeeId);
            if (employeeEnitiy == null)
            {
                //那么就新增一个资源
                var employeeToAddEntity = mapper.Map<Employee>(updateDto);
                employeeToAddEntity.Id = employeeId;
                _companyRepository.AddEmployee(companyId, employeeToAddEntity);
                await _companyRepository.SaveAsync();

                var employeeDto = mapper.Map<EmployeeDto>(employeeToAddEntity);
                return CreatedAtRoute(nameof(GetEmployeeForComapn), new { companyId, employeeid = employeeDto.Id }, employeeDto);
            }
            mapper.Map(updateDto, employeeEnitiy);
            _companyRepository.UpdataEmployee(employeeEnitiy);
            await _companyRepository.SaveAsync();
            return Ok(employeeEnitiy);
        }

        [HttpPatch("{employeeId}")]
        public async Task<IActionResult> PartiallyUpdateEmploye(
            Guid companyId,
            Guid employeeId,
            JsonPatchDocument<EmployeeUpdateDto> patchDocument)
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
                return NotFound();
            var employeeEnitiy = await _companyRepository.GetEmployeeAsync(companyId, employeeId);
            if (employeeEnitiy == null)
            {
                //找不到这个员工 就按照传入进来的id新建一个员工
                var employeeDto = new EmployeeUpdateDto();
                patchDocument.ApplyTo(employeeDto, ModelState);
                if (!TryValidateModel(employeeDto))
                {
                    return ValidationProblem(ModelState);
                }
                var emplyeeToAdd = mapper.Map<Employee>(employeeDto);
                emplyeeToAdd.Id = employeeId;
                _companyRepository.AddEmployee(companyId, emplyeeToAdd);
                await _companyRepository.SaveAsync();

                var reemployeeDto = mapper.Map<EmployeeDto>(emplyeeToAdd);
                return CreatedAtRoute(nameof(GetEmployeeForComapn), new { companyId, employeeid = reemployeeDto.Id }, reemployeeDto);
            }

            var dtoToPatch = mapper.Map<EmployeeUpdateDto>(employeeEnitiy);

            patchDocument.ApplyTo(dtoToPatch,ModelState);

            //需要手动处理模型的验证错误
            if (!TryValidateModel(dtoToPatch))
            {
                return ValidationProblem(ModelState);
            }

            mapper.Map(dtoToPatch, employeeEnitiy);
            _companyRepository.UpdataEmployee(employeeEnitiy);
            await _companyRepository.SaveAsync();
            return Ok(employeeEnitiy);

        }


        [HttpDelete("{employeeid}")]           
        public async Task<IActionResult> DeleteEmployeeForCompany(Guid companyId, Guid employeeId)
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
                return NotFound();

            var employeeEnitiy = await _companyRepository.GetEmployeeAsync(companyId, employeeId);
            if (employeeEnitiy == null)
                return NotFound();

            _companyRepository.DeleteEmployee(employeeEnitiy);
            await _companyRepository.SaveAsync();

            return NoContent();

        }
        public override ActionResult ValidationProblem([ActionResultObjectValue] ModelStateDictionary modelStateDictionary)
        {
            var options = HttpContext.RequestServices.GetRequiredService<IOptions<ApiBehaviorOptions>>();
            return (ActionResult)options.Value.InvalidModelStateResponseFactory(ControllerContext);
        }

    }
}
